package ar.com.arkios.kfcon4d.util;

import ar.com.arkios.j4d.opConstants;
import ar.com.arkios.j4d.opData;
import ar.com.arkios.j4d.opDataArray;
import ar.com.arkios.j4d.opField;
import ar.com.arkios.j4d.opFieldArray;
import ar.com.arkios.j4d.opTable;
import java.util.List;
import org.apache.log4j.Logger;

/**
 * <p>
 * Esta clase provee métodos auxiliares para facilitar la búsqueda y armado de
 * las estructuras utilizadas por la API de 4D Open.
 * </p>
 */
public class EstructuraUtil {

    private static final Logger miLogger = Logger.getLogger(EstructuraUtil.class);
    
    /**
     * Constante utilizada para indicar que no se encontró el campo solicitado.
     */
    public static final int NO_FIELD_FOUND = -1;

    // TODO: esto debería ir en otra parte.
    public static final String[] misTablas4D = {"Especies", "EspeciesAtributos", "Variedades", "VariedadesAtributos",
    "Envases", "EnvasesAtributos", "Tamaños", "TamanosAtributos", "Embalajes", "EmbalajesAtributos", "AreasDeStock", 
    "LeyendaEtiquetas", "EAN", "Contramarcas", "EnvasesPeso", "LoteGranel", "OrdenesSAP"};
    
    public static final String SAP = "SAP";
    
    /**
     * <p>
     * Crea un opFieldArray conteniendo las columnas especificadas de la tabla
     * pasada por parámetro.
     * </p>
     * 
     * <p>
     * En caso de no que la tabla no contenga una de las columnas que se indique
     * por parámetro, se obviará la misma. El usuario deberá validar de ser 
     * necesario que se obtengan todas las columnas que se pidieron comparando
     * los tamaños del array devuelto y el de las columnas solicitadas.
     * </p>
     * 
     * @param table opTable que contiene todos los datos de la tabla en la cual 
     * se van a buscar los campos solicitados.
     * @param columnas nombre de las columnas que se desean obtener de la tabla.
     * Estos serán devueltos en un opFieldArray.
     * 
     * @return un opFieldArray conteniendo todos los campos de la tabla
     */
    public static opFieldArray getFieldArrayFor(opTable table, String[] columnas) {
        if (columnas.length > 0) {
            // Inicializo el field array resultante.
            opFieldArray fieldArray = new opFieldArray(columnas.length);
            fieldArray.mTargetTable = table.mTableNumber;
            
            // Agrego las columnas indicadas al field array.
            int i = 0;
            for (String nombreColumna : columnas) {
                opField field = findField(table.mFieldList, nombreColumna);
                if (field != null)
                    fieldArray.mFieldArray[i++] = field;
            }
            
            return fieldArray;
        }
        
        return null;
    }
    
    /**
     * <p>
     * Obtiene el campo (field) con el nombre indicado por parámetro existente 
     * en el opFieldArray.
     * </p>
     * 
     * @param fieldArray array de campos en el que se va a buscar.
     * @param fieldName nombre del campo (field) que se está buscando en el 
     * array. El nombre que se indica por parámetro debe corresponder al nombre 
     * físico de la columna que esta siendo representada por el opField buscado.
     * 
     * @return el opField correspondiente al campo cuyo nombre es el indicado
     * por parámetro. En caso de no existir ningún campo con el nombre indicado
     * se devuelve <i>null</i>.
     */
    public static opField findField(opFieldArray fieldArray, String fieldName) {
        for (opField field : fieldArray.mFieldArray) {
            if (field.mFieldName.equals(fieldName)) {
                return field;
            }
        }
        
        return null;
    }
    
    /**
     * <p>
     * Obtiene el número identificatorio del campo de la tabla que corresponde 
     * al nombre indicado.
     * </p>
     * 
     * <p>
     * En caso de no encontrar el campo en la tabla con el nombre especificado
     * se devuelve la constante NO_FIELD_FOUND.
     * </p>
     * 
     * @param table opTable que representa la tabla en 4D. La misma debe 
     *      contener todos los datos de la tabla.
     * @param fieldName nombre del campo del cual se desea obtener el número
     *      identificatorio.
     * 
     * @return número identificatorio del campo solicitado o NO_FIELD_FOUND en 
     *      caso de no encontrar el mismo.
     */
    public static short getFieldNumber(opTable table, String fieldName) {
        opField field = findField(table.mFieldList, fieldName);
        return (field != null) ? field.mFieldNumber : NO_FIELD_FOUND;
    }
    
    /**
     * <p>
     * Devuelve la posición dentro del opFieldArray en la que se encuentra el 
     * campo cuyo nombre es el indicado por parámetro.
     * </p>
     * 
     * @param fieldArray opFieldArray donde se buscará el campo solicitado.
     * @param fieldName nombre del campo que se está buscando.
     * 
     * @return posición dentro del opFieldArray donde se encuentra el campo con
     *      el nombre indicado. En caso de no encontrar el campo dentro del 
     *      opFiledArray se devuelve NO_FIELD_FOUND.
     */
    public static int getFieldPosition(opFieldArray fieldArray, String fieldName) {
        int pos = 0;
        
        for (opField field : fieldArray.mFieldArray) {
            if (field.mFieldName.equals(fieldName)) {
                return pos;
            } else {
                pos++;
            }
        }
        
        return NO_FIELD_FOUND;
    }
    
    /**
     * Crea un opDataArray que contiene los valores de los elementos de la lista
     * indicada por parámetros. Dichos valores se cargan en el opDAtaArray como
     * String, es decir, 4D los va a tomar como ALPHANUMERIC.
     * 
     * @param claves
     * @return
     */
    public static opDataArray[] getStringPKDataArray(List<String> claves) {
        opDataArray[] result = new opDataArray[1];
        result[0] = new opDataArray(claves.size());
        
        int i = 0;
        for (String clave : claves) {
            result[0].mDataArray[i] = new opData(opConstants.ALPHANUMERIC, clave);
            i++;
        }
        
        return result;
    }
    
    /**
     * Crea un opDataArray que contiene los valores de los elementos de la lista
     * indicada por parámetros. Dichos valores se cargan en el opDAtaArray como
     * Integer, es decir, 4D los va a tomar como LONGINTEGER.
     * 
     * @param claves
     * @return
     */
    public static opDataArray[] getIntegerPKDataArray(List<String> claves) {
        opDataArray[] result = new opDataArray[1];
        result[0] = new opDataArray(claves.size());
        
        int i = 0;
        for (String clave : claves) {
            try {
                result[0].mDataArray[i] = new opData(opConstants.LONGINTEGER, Integer.valueOf(clave).intValue());
            } catch (NumberFormatException e) {
                miLogger.error("No se pudo convertir el valor " + clave + " a número.");
                throw e;
            }
                    
            i++;
        }
        
        return result;
    }
    
}
